package com.dianping.cat.consumer.config;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.codehaus.plexus.logging.LogEnabled;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.unidal.dal.jdbc.DalException;
import org.unidal.dal.jdbc.DalNotFoundException;
import org.unidal.lookup.annotation.Inject;
import org.unidal.lookup.annotation.Named;
import org.xml.sax.SAXException;

import com.dianping.cat.Cat;
import com.dianping.cat.config.content.ContentFetcher;
import com.dianping.cat.consumer.all.config.entity.AllConfig;
import com.dianping.cat.consumer.all.config.entity.Name;
import com.dianping.cat.consumer.all.config.entity.Report;
import com.dianping.cat.consumer.all.config.entity.Type;
import com.dianping.cat.consumer.all.config.transform.DefaultSaxParser;
import com.dianping.cat.core.config.Config;
import com.dianping.cat.core.config.ConfigDao;
import com.dianping.cat.core.config.ConfigEntity;
import com.dianping.cat.task.TimerSyncTask;
import com.dianping.cat.task.TimerSyncTask.SyncHandler;

@Named
public class AllReportConfigManager implements Initializable, LogEnabled {

    private static final String CONFIG_NAME = "all-report-config";

    @Inject
    private ConfigDao m_configDao;

    @Inject
    private ContentFetcher m_fetcher;

    private int m_configId;

    private volatile AllConfig m_config;

    private Logger m_logger;

    private long m_modifyTime;

    @Override
    public void enableLogging(Logger logger) {
        m_logger = logger;
    }

    public AllConfig getConfig() {
        return m_config;
    }

    @Override
    public void initialize() throws InitializationException {
        try {
            Config config = m_configDao.findByName(CONFIG_NAME, ConfigEntity.READSET_FULL);
            String content = config.getContent();

            m_configId = config.getId();
            m_config = DefaultSaxParser.parse(content);
            m_modifyTime = config.getModifyDate().getTime();
        } catch (DalNotFoundException e) {
            try {
                String content = m_fetcher.getConfigContent(CONFIG_NAME);
                Config config = m_configDao.createLocal();
                Date now = new Date();

                config.setName(CONFIG_NAME);
                config.setContent(content);
                config.setModifyDate(now);
                m_configDao.insert(config);

                m_configId = config.getId();
                m_config = DefaultSaxParser.parse(content);
                m_modifyTime = now.getTime();
            } catch (Exception ex) {
                Cat.logError(ex);
            }
        } catch (Exception e) {
            Cat.logError(e);
        }
        if (m_config == null) {
            m_config = new AllConfig();
        }

        TimerSyncTask.getInstance().register(new SyncHandler() {

            @Override
            public void handle() throws Exception {
                refreshConfig();
            }

            @Override
            public String getName() {
                return CONFIG_NAME;
            }
        });
    }

    public boolean insert(String xml) {
        try {
            m_config = DefaultSaxParser.parse(xml);
            boolean result = storeConfig();

            return result;
        } catch (Exception e) {
            Cat.logError(e);
            m_logger.error(e.getMessage(), e);
            return false;
        }
    }

    private void refreshConfig() throws DalException, SAXException, IOException {
        Config config = m_configDao.findByName(CONFIG_NAME, ConfigEntity.READSET_FULL);
        long modifyTime = config.getModifyDate().getTime();

        synchronized (this) {
            if (modifyTime > m_modifyTime) {
                String content = config.getContent();
                m_config = DefaultSaxParser.parse(content);
                m_modifyTime = modifyTime;
            }
        }
    }

    private boolean storeConfig() {
        synchronized (this) {
            try {
                Config config = m_configDao.createLocal();

                config.setId(m_configId);
                config.setKeyId(m_configId);
                config.setName(CONFIG_NAME);
                config.setContent(m_config.toString());
                m_configDao.updateByPK(config, ConfigEntity.UPDATESET_FULL);
            } catch (Exception e) {
                Cat.logError(e);
                return false;
            }
        }
        return true;
    }

    public boolean validate(String reportName, String type) {
        Report report = m_config.getReports().get(reportName);

        if (report != null) {
            Map<String, Type> types = report.getTypes();

            return types.containsKey(type) || types.containsKey("*");
        } else {
            return false;
        }
    }

    public boolean validate(String reportName, String type, String name) {
        Report report = m_config.getReports().get(reportName);

        if (report != null) {
            Map<String, Type> types = report.getTypes();
            Type typeConfig = types.get(type);

            if (typeConfig != null) {
                List<Name> list = typeConfig.getNameList();

                for (Name nameConfig : list) {
                    String configId = nameConfig.getId();

                    if (configId.equals(name) || "*".equals(configId)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

}